<template>
  <div>
    <a-upload
      :list-type="computedListType"
      :multiple="multiple"
      :max-count="maxCount"
      :accept="accept"
      :file-list="fileList"
      :custom-request="doCustomRequest"
      :before-upload="beforeUpload"
      :disabled="disabled || readOnly"
      @change="onChange"
      @preview="onPreview"
    >
      <template v-if="computedListType === 'picture-card'">
        <div>
          <PlusOutlined />
          <div style="margin-top:8px">{{ buttonText || (fileType === 'image' ? '上传图片' : '上传文件') }}</div>
        </div>
      </template>
      <template v-else>
        <a-button type="dashed">{{ buttonText || (fileType === 'image' ? '上传图片' : '上传文件') }}</a-button>
      </template>
    </a-upload>

    <a-modal v-model:open="previewOpen" footer="null">
      <a-image v-if="previewImage" :src="previewImage" :preview="false" style="width:100%" />
    </a-modal>
  </div>
  
</template>

<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import type { UploadChangeParam, UploadFile, UploadProps, UploadRequestOption } from 'ant-design-vue'
import { PlusOutlined } from '@ant-design/icons-vue'
import { uploadFile } from '@/api/upload'

const props = withDefaults(defineProps<{
  modelValue?: string | string[]
  fileType?: 'image' | 'file'
  multiple?: boolean
  listType?: UploadProps['listType']
  maxCount?: number
  accept?: string
  buttonText?: string
  maxSizeMB?: number
  whitelist?: string[]
  disabled?: boolean
  readOnly?: boolean
}>(), {
  modelValue: undefined,
  fileType: 'image',
  multiple: false,
  listType: undefined,
  maxCount: 1,
  accept: undefined,
  buttonText: '',
  maxSizeMB: 10,
  whitelist: undefined,
  disabled: false,
  readOnly: false
})

const emit = defineEmits<{
  (e: 'update:modelValue', v?: string | string[]): void
  (e: 'uploaded', url: string): void
}>()

const previewOpen = ref(false)
const previewImage = ref('')
const fileList = ref<UploadFile<any>[]>([])

const computedListType = computed<UploadProps['listType']>(() => {
  if (props.listType) return props.listType
  return props.fileType === 'image' ? 'picture-card' : 'text'
})

watch(() => props.modelValue, (val) => {
  if (val == null) { fileList.value = []; return }
  if (Array.isArray(val)) {
    fileList.value = val.map((url, idx) => ({ uid: String(idx), name: url.split('/').pop() || `file-${idx}`, status: 'done', url }))
  } else if (typeof val === 'string' && val) {
    fileList.value = [{ uid: '0', name: val.split('/').pop() || 'file', status: 'done', url: val }]
  } else {
    fileList.value = []
  }
}, { immediate: true })

function beforeUpload(file: File) {
  if (props.readOnly || props.disabled) return false
  if (props.fileType === 'image' && !file.type.startsWith('image/')) return false
  if (props.whitelist && props.whitelist.length) {
    const ok = props.whitelist.some((ext) => file.name.toLowerCase().endsWith(ext.toLowerCase()))
    if (!ok) return false
  }
  if (props.maxSizeMB && file.size > props.maxSizeMB * 1024 * 1024) return false
  return true
}

async function doCustomRequest(options: UploadRequestOption) {
  try {
    const file = options.file as File
    const { url } = await uploadFile(file)
    options.onSuccess && options.onSuccess({ url } as any, file as any)
    emit('uploaded', url)
  } catch (e) {
    options.onError && options.onError(e as any)
  }
}

function onChange(info: UploadChangeParam) {
  const fl = info.fileList
  // 同步到外部 v-model
  const urls = fl.filter(f => f.status === 'done' && (f.url || (f.response as any)?.url))
                .map(f => f.url || (f.response as any)?.url)
                .filter(Boolean) as string[]
  if (props.multiple || props.maxCount && props.maxCount > 1) {
    emit('update:modelValue', urls)
  } else {
    emit('update:modelValue', urls[0])
  }
}

function onPreview(file: UploadFile) {
  if (props.fileType !== 'image') return
  const url = file.url || (file.response as any)?.url
  if (!url) return
  previewImage.value = url
  previewOpen.value = true
}

</script>

<style scoped>
</style>


